package com.meida.app.provider.controller;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.meida.app.provider.handler.LoginHandler;
import com.meida.common.annotation.RlockRepeat;
import com.meida.common.constants.CommonConstants;
import com.meida.common.lock.LockConstant;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.oauth2.OpenOAuth2ClientDetails;
import com.meida.common.oauth2.OpenOAuth2ClientProperties;
import com.meida.common.security.OpenHelper;
import com.meida.common.springmvc.base.BaseController;
import com.meida.common.utils.ApiAssert;
import com.meida.common.utils.SpringContextHolder;
import com.meida.module.user.client.dto.LoginParams;
import com.meida.module.user.client.entity.AppUser;
import com.meida.module.user.provider.service.AppUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author: zyf
 * @date: 2018/11/9 15:43
 * @description:
 */
@Api(tags = "登录注册")
@RestController
public class AppLoginController extends BaseController<AppUserService, AppUser> {


    @Autowired
    private AppUserService userService;

    @Autowired
    private OpenOAuth2ClientProperties clientProperties;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    AuthorizationServerEndpointsConfiguration endpoints;

    /**
     * app登录
     */
    @ApiOperation(value = "登录", position = 1, notes = "登录成功后获取access_token,并调用初始化登录接口")
    @PostMapping("/login/token")
    public Object getLoginToken(LoginParams loginParams, @RequestHeader HttpHeaders headers) throws Exception {
        ResultBody resultBody = new ResultBody();
        OpenOAuth2ClientDetails clientDetails = clientProperties.getOauth2().get("portal");
        ApiAssert.isNotEmpty("用户名不能为空", loginParams.getUsername());
        LoginHandler loginHandler = SpringContextHolder.getHandler(loginParams.getHandlerName(), LoginHandler.class);
        Boolean hanHandler = false;
        if (ObjectUtils.isNotEmpty(loginHandler)) {
            hanHandler = true;
            //执行校验
            resultBody = loginHandler.beforLogin(loginParams);
        }
        if (resultBody.isOk()) {
            // 使用oauth2密码模式登录.
            Map<String, String> postParameters = new HashMap<>();
            postParameters.put("username", loginParams.getUsername());
            postParameters.put("password", loginParams.getPassword());
            postParameters.put("accountType", loginParams.getAccountType());
            postParameters.put("avatar", loginParams.getAvatar());
            postParameters.put("nickName", loginParams.getNickName());
            postParameters.put("client_id", clientDetails.getClientId());
            postParameters.put("client_secret", clientDetails.getClientSecret());
            postParameters.put("grant_type", "password");
            // 使用客户端的请求头,发起请求
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            // 强制移除 原来的请求头,防止token失效
            headers.remove(HttpHeaders.AUTHORIZATION);
            HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity(postParameters, headers);
 /*       JSONObject result = openRestTemplate.postForObject("http://localhost:7211/oauth/token", request, JSONObject.class);
        if (ObjectUtils.isNotEmpty(request) && result.containsKey("access_token")) {
            result.put("access_token", "Bearer " + result.get("access_token"));
            return ResultBody.ok(result);
        }
        return result;*/
            Map<String, Object> map = new HashMap<>();
            OAuth2AccessToken oAuth2AccessToken = OpenHelper.createAccessToken(endpoints, postParameters);
            if (ObjectUtils.isNotEmpty(oAuth2AccessToken)) {
                map.put("access_token", "Bearer " + oAuth2AccessToken.getValue());
                map.put("token_type", oAuth2AccessToken.getTokenType());
                map.put("expires_in", oAuth2AccessToken.getExpiresIn());
                map.put("refresh_token", Optional.ofNullable(oAuth2AccessToken.getRefreshToken()).orElse(() -> "").getValue());
                map.putAll(oAuth2AccessToken.getAdditionalInformation());
                if (hanHandler) {
                    resultBody = loginHandler.afterLogin(map, loginParams);
                }
            }
            if (resultBody.isOk()) {
                return resultBody.data(map);
            }
        }
        return resultBody;
    }

    /**
     * 退出移除令牌
     *
     * @param token
     */
    @ApiOperation(value = "退出并移除令牌", notes = "退出并移除令牌,令牌将失效")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", required = true, value = "访问令牌", paramType = "form")
    })
    @PostMapping("/logout/token")
    public ResultBody removeToken(@RequestParam String token) {
        tokenStore.removeAccessToken(tokenStore.readAccessToken(token));
        return ResultBody.ok();
    }

    /**
     * 初始化登录
     */
    @ApiOperation(value = "初始化登录", notes = "登录成功后调用该方法")
    @GetMapping("/user/userInit")
    public ResultBody<AppUser> userInit(@RequestParam(required = false) Map params) {
        return bizService.userInit(params);
    }

    /**
     * 注册账户
     */
    @ApiOperation(value = "注册账户", notes = "注册会员账户")
    @PostMapping(value = "/login/registerAccount")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accountName", value = "账户名", paramType = "form"),
            @ApiImplicitParam(name = "telephone", value = "手机号", paramType = "form"),
            @ApiImplicitParam(name = "userType", value = "用户类型", paramType = "form"),
            @ApiImplicitParam(name = "smsCode", value = "验证码", paramType = "form", defaultValue = "18739941307"),
            @ApiImplicitParam(name = "password", value = "密码(选填)", paramType = "form"),
            @ApiImplicitParam(name = "userName", value = "用户名(选填)", paramType = "form"),
            @ApiImplicitParam(name = "nickName", value = "昵称(选填)", paramType = "form"),
            @ApiImplicitParam(name = "email", value = "邮箱(选填)", paramType = "form"),
            @ApiImplicitParam(name = "companyName", value = "企业名称(选填)", paramType = "form"),
            @ApiImplicitParam(name = "inviter", value = "邀请人(选填)", paramType = "form")
    })
    @RlockRepeat(prefix = "register", lockConstant = LockConstant.SUBMIT)
    public ResultBody registerAccount(@RequestParam(required = false) Map params,
                                      @RequestParam(value = "accountName", required = false) String accountName,
                                      @RequestParam(value = "telephone", required = false) String telephone,
                                      @RequestParam(value = "smsCode", required = false) String smsCode,
                                      @RequestParam(value = "userType", defaultValue = "USER") String userType,
                                      @RequestParam(value = "password", required = false, defaultValue = CommonConstants.DEF_PWD) String password,
                                      @RequestParam(value = "areaCode", required = false, defaultValue = "+86") String areaCode,
                                      @RequestParam(value = "userName", required = false) String userName,
                                      @RequestParam(value = "nickName", required = false) String nickName,
                                      @RequestParam(value = "companyName", required = false) String companyName,
                                      @RequestParam(value = "email", required = false) String email,
                                      @RequestParam(value = "handlerName", required = false) String handlerName,
                                      @RequestParam(value = "inviter", required = false) String inviter
    ) {

        return userService.registerAccount(params, accountName, telephone, areaCode, smsCode, userType, password, userName, nickName, email, companyName, inviter, handlerName);
    }

    /**
     * 获取当前登录用户信息-SSO单点登录
     *
     * @param principal
     * @return
     */
    @ApiOperation(value = "获取当前登录用户信息-SSO单点登录", notes = "获取当前登录用户信息-SSO单点登录")
    @GetMapping("/current/user/sso")
    public Principal principal(Principal principal) {
        return principal;
    }
}
